// $Id: ptr.cpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#include <boost/test/unit_test.hpp>
#include <xpcom/impl/ptr.hpp>
#include "interface_def.hpp"

namespace xpcom {
namespace {

void do_in_impl_1(noref_ptr<IA> p)
{
    BOOST_CHECK(!p);
}

void do_in_1(IA* p)
{
    do_in_impl_1(impl::ptr_in(p));
}

void do_in_impl_2(noref_ptr<IA> p)
{
    BOOST_CHECK(p);
    BOOST_CHECK(p->getN() == 9);
}

void do_in_2(IA* p)
{
    do_in_impl_2(impl::ptr_in(p));
}

void do_out_impl_1(ref_ptr<IBase>& p)
{
    BOOST_CHECK(!p);
    p.reset(X_make_instance());
    p->setN(8);
}

void do_out_1(IBase** p)
{
    do_out_impl_1(impl::ptr_out(p));
}

void do_out_impl_2(ref_ptr<IBase>& p)
{
    BOOST_CHECK(!p);
    p.reset();
}

void do_out_2(IBase** p)
{
    do_out_impl_2(impl::ptr_out(p));
}

ref_ptr<IBase> do_out_impl_retval()
{
    ref_ptr<IBase> p(X_make_instance());
    p->setN(9);
    return p;
}

void do_out_retval(IBase** p)
{
    impl::ptr_out(p) = do_out_impl_retval();
}

void do_inout_impl_1(ref_ptr<IBase>& p)
{
    BOOST_CHECK(!p);
    p.reset(X_make_instance());
    p->setN(30);
}

void do_inout_1(IBase** p)
{
    do_inout_impl_1(impl::ptr_inout(p));
}

void do_inout_impl_2(ref_ptr<IBase>& p)
{
    BOOST_CHECK(p);
    BOOST_CHECK_EQUAL(p->getN(), 40);
    p->setN(50);
}

void do_inout_2(IBase** p)
{
    do_inout_impl_2(impl::ptr_inout(p));
}

void do_inout_impl_3(ref_ptr<IBase>& p)
{
    BOOST_CHECK(p);
    BOOST_CHECK_EQUAL(p->getN(), 60);

    p.reset(X_make_instance());
    p->setN(70);
}

void do_inout_3(IBase** p)
{
    do_inout_impl_3(impl::ptr_inout(p));
}

void do_inout_impl_4(ref_ptr<IBase>& p)
{
    BOOST_CHECK(p);
    BOOST_CHECK_EQUAL(p->getN(), 80);
    p.reset();
}

void do_inout_4(IBase** p)
{
    do_inout_impl_4(impl::ptr_inout(p));
}

}
}

BOOST_AUTO_TEST_CASE(test_ptr_in)
{
    using namespace xpcom;

    X_count_guard g;
    X_count(0);
    {
        IA* p = 0;
        do_in_1(p);

        p = static_cast<IA*>(X_make_instance());
        p->setN(9);
        do_in_2(p);

        ref_ptr<IA> ref_p(p);

        BOOST_CHECK_EQUAL(X_count(), 1);
    }
    BOOST_CHECK_EQUAL(X_count(), 0);
}

BOOST_AUTO_TEST_CASE(test_ptr_out)
{
    using namespace xpcom;

    X_count_guard g;
    X_count(0);
    {
        IBase* p;

        do_out_1(&p);
        BOOST_CHECK_EQUAL(X_count(), 1);
        BOOST_CHECK(p != 0);
        BOOST_CHECK_EQUAL(p->getN(), 8);
        p->release();

        do_out_2(&p);
        BOOST_CHECK_EQUAL(X_count(), 0);
        BOOST_CHECK(p == 0);

        do_out_retval(&p);
        BOOST_CHECK_EQUAL(X_count(), 1);
        BOOST_CHECK(p != 0);
        BOOST_CHECK_EQUAL(p->getN(), 9);
        p->release();
    }
    BOOST_CHECK_EQUAL(X_count(), 0);
}

BOOST_AUTO_TEST_CASE(test_ptr_inout)
{
    using namespace xpcom;

    X_count_guard g;
    X_count(0);
    {
        IBase* p = 0;

        do_inout_1(&p);
        BOOST_CHECK_EQUAL(X_count(), 1);
        BOOST_CHECK(p != 0);
        BOOST_CHECK_EQUAL(p->getN(), 30);

        p->setN(40);
        do_inout_2(&p);
        BOOST_CHECK_EQUAL(X_count(), 1);
        BOOST_CHECK(p != 0);
        BOOST_CHECK_EQUAL(p->getN(), 50);

        p->setN(60);
        do_inout_3(&p);
        BOOST_CHECK_EQUAL(X_count(), 1);
        BOOST_CHECK(p != 0);
        BOOST_CHECK_EQUAL(p->getN(), 70);

        p->setN(80);
        do_inout_4(&p);
        BOOST_CHECK_EQUAL(X_count(), 0);
        BOOST_CHECK(p == 0);
    }
    BOOST_CHECK_EQUAL(X_count(), 0);
}
